【Pythonでゲームを作ろう!】レトロな2Dゲームを作ってみた!
2019.10.30 追記:成果物がゲーム要素に乏しかったのでもう少しちゃんと遊べるものに改良しました。たくさんの方に読んでいただけて恐縮です。少しでも使い方の参考になれれば嬉しいです。
Pyxelとは
ピクセルアートのレトロな2Dゲームが作れるPythonライブラリです。
・仕様
- Mac, Windows, Linux対応
- 同時に再生できる音は4音
- 使用できる色は16色のみ、定義可能な64サウンド
- Python3によるコード記述
- 256x256サイズ、3画像バンク
- 256x256サイズ、8タイルマップ
- 任意のサウンドを組み合わせ可能な8ミュージック
- キーボード、マウス、ゲームパッド
- 画像・サウンド編集ツール
pyxel/README.ja.md at master · kitao/pyxel · GitHub
ドット絵がうてるツールや、音楽を作成できるツールも入っており、ゼロからゲームを作ることができます。
シンプルな造りで初心者でも簡単にゲームを作ることができる仕様になっています。
Install
必要なもの:
- Python3.7 以上
- Homebrew
brew install python3 sdl2 sdl2_image pip3 install -U pyxel
pyxel/README.ja.md at master · kitao/pyxel · GitHub
サンプルを動かしてみる
サンプルをインストール
install_pyxel_examples
ファイルを指定して実行
cd pyxel_examples python3 01_hello_pyxel.py
レトロな雰囲気がたまらないですね!
ドット風のフォントもかわいいです。
使ってみた
ドキュメントを読みながら色々試してみました。
アセットはサンプルプロジェクトの物をお借りしています。
猫を表示させる
import pyxel class App: def __init__(self): pyxel.init(160, 120, caption="Hello Pyxel") pyxel.image(0).load(0, 0, "assets/cat_16x16.png") pyxel.run(self.update, self.draw) def update(self): if pyxel.btnp(pyxel.KEY_Q): pyxel.quit() def draw(self): pyxel.cls(0) pyxel.blt(75, 45, 0, 0, 0, 16, 16) App()
pixel.init(width, height, )
init(width, height, , [scale], [palette], [fps], [border_width], [border_color])
- width、height: 画面サイズを指定(画面の最大の幅と高さは255)。
- caption:ウィンドウのタイトルを指定
- scale:表示倍率を指定
- palette:パレット色を指定
- fps:動作フレームレートを指定
- border_width、border_color:画面外側のマージン幅と色を指定
pixel.run(update, draw)
Pyxelアプリを開始する関数。フレーム更新時にupdate関数、描画時にdraw関数を呼び出す。
猫の背景を透過
先ほど実行したサンプルでは猫の背景が透過していません。
pyxel.blt()
の[colorkey]オプションで透過色を設定することができます。
先ほどの猫の画像は5の色が背景色なので、透過色に5を指定します。
pyxel.blt(75, 45, 0, 0, 0, 16, 16, 5)
Player(猫ちゃん)を動かす
キーボード操作で左右に猫ちゃんを動かしてみます。
import pyxel class App: def __init__(self): pyxel.init(160, 120, caption="Hello Pyxel") pyxel.image(0).load(0, 0, "assets/cat_16x16.png") # Starting Point self.player_x = 72 self.player_y = 16 pyxel.run(self.update, self.draw) def update(self): if pyxel.btnp(pyxel.KEY_Q): pyxel.quit() self.update_player() def update_player(self): if pyxel.btn(pyxel.KEY_LEFT) or pyxel.btn(pyxel.GAMEPAD_1_LEFT): self.player_x = max(self.player_x - 2, 0) if pyxel.btn(pyxel.KEY_RIGHT) or pyxel.btn(pyxel.GAMEPAD_1_RIGHT): self.player_x = min(self.player_x + 2, pyxel.width - 16) if pyxel.btn(pyxel.KEY_UP) or pyxel.btn(pyxel.GAMEPAD_1_UP): self.player_y = max(self.player_y - 2, 0) if pyxel.btn(pyxel.KEY_DOWN) or pyxel.btn(pyxel.GAMEPAD_1_DOWN): self.player_y = min(self.player_y + 2, pyxel.height - 16) def draw(self): pyxel.cls(0) # 猫ちゃんを描写 pyxel.blt( self.player_x, self.player_y, 0, 0, 0, 16, 16, 5, ) App()
実行結果:
フルーツを出現させてみる
猫ちゃんがお腹が空いてしまってはかわいそうなのでフルーツを出してあげましょう。
アセットを追加
pyxeleditor
を使ってアセットを作成します。
作成したアセットを利用する
pyxeleditor
で作成したアセットは.pyxres
形式のファイルにまとめられます。
使用したいアセットを指定して利用します。
指定方法:
blt(x, y, img, u, v, w, h, [colkey])
イメージバンクimg(0-2) の (u, v) からサイズ (w, h) の領域を (x, y) にコピーする。w、hそれぞれに負の値を設定すると水平、垂直方向に反> 転する。colkeyに色を指定すると透明色として扱われる
公式ドキュメントから引用
リンゴを利用したい場合は(16, 0)
を指定します。
成果物
pyxel_examples
のプロジェクトを参考に当たり判定やスコア機能などを追加してみました。
ソースコード
丸ごと置いておきます。
ゲームプログラミングに関しては完全に初心者なので、冗長な記述は大目に見ていただければと思います。
from collections import deque, namedtuple from random import randint import pyxel Point = namedtuple("Point", ["w", "h"]) # 猫の向き UP = Point(-16, 16) DOWN = Point(16, 16) RIGHT = Point(-16, 16) LEFT = Point(16, 16) class App: def __init__(self): pyxel.init(160, 120, caption="Hello Pyxel") pyxel.load("assets/hello2.pyxres") self.direction = RIGHT # Score self.score = 0 # Starting Point self.player_x = 42 self.player_y = 60 self.player_vy = 0 self.fruit = [(i * 60, randint(0, 104), True) for i in range(4)] pyxel.playm(0, loop=True) pyxel.run(self.update, self.draw) def update(self): if pyxel.btnp(pyxel.KEY_Q): pyxel.quit() self.update_player() for i, v in enumerate(self.fruit): self.fruit[i] = self.update_fruit(*v) def update_player(self): if pyxel.btn(pyxel.KEY_LEFT) or pyxel.btn(pyxel.GAMEPAD_1_LEFT): self.player_x = max(self.player_x - 2, 0) self.direction = LEFT if pyxel.btn(pyxel.KEY_RIGHT) or pyxel.btn(pyxel.GAMEPAD_1_RIGHT): self.player_x = min(self.player_x + 2, pyxel.width - 16) self.direction = RIGHT if pyxel.btn(pyxel.KEY_UP) or pyxel.btn(pyxel.GAMEPAD_1_UP): self.player_y = max(self.player_y - 2, 0) self.direction = UP if pyxel.btn(pyxel.KEY_DOWN) or pyxel.btn(pyxel.GAMEPAD_1_DOWN): self.player_y = min(self.player_y + 2, pyxel.height - 16) self.direction = DOWN def draw(self): # bg color pyxel.cls(12) # draw fruits for x, y, is_active in self.fruit: if is_active: pyxel.blt(x, y, 0, 16, 0, 16, 16, 5) # draw cat pyxel.blt( self.player_x, self.player_y, 0, 16 if self.player_vy > 0 else 0, 0, self.direction[0], self.direction[1], 5, ) # スコアを表示 s = "Score {:>4}".format(self.score) pyxel.text(5, 4, s, 1) pyxel.text(4, 4, s, 7) def update_fruit(self, x, y, is_active): if is_active and abs(x - self.player_x) < 12 and abs(y - self.player_y) < 12: is_active = False self.score += 100 self.player_vy = min(self.player_vy, -8) pyxel.play(3, 4) x -= 2 if x < -40: x += 240 y = randint(0, 104) is_active = True return (x, y, is_active) App()
所感
今回作成したものはとても簡単なものではありますが遊べるものを作ることができました。音楽を作るツールも内蔵されているので引き続き使ってみようと思います。